package pers.ijfxu.testngext.dataprovider.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.db.ds.simple.SimpleDataSource;
import cn.hutool.db.handler.EntityListHandler;
import cn.hutool.db.sql.SqlExecutor;
import pers.ijfxu.testngext.context.RunContext;
import pers.ijfxu.testngext.dataprovider.IDataProv;
import pers.ijfxu.testngext.dataprovider.IteratorFactory;
import pers.ijfxu.testngext.dataprovider.Sql;
import pers.ijfxu.testngext.dataprovider.TestDataCollection;
import pers.ijfxu.testngext.log.RePorterLog;

import org.slf4j.LoggerFactory;
import org.testng.annotations.DataProvider;

import javax.sql.DataSource;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;

import static java.util.Objects.isNull;
import static pers.ijfxu.testngext.utils.PathUtils.*;
import static pers.ijfxu.testngext.utils.StrUtils.empty;

 /**
 * 自定义TestNG DataProviderClass 统一入口类
 *
 * @author ijfxu  
 * @since 2021/1/27 00:17
 */
public class DataProv implements IDataProv {
    RePorterLog log = RePorterLog.getLogger(LoggerFactory.getLogger(this.getClass()));

    /**
     * 数据工厂函数，返回测试入参迭代器对象;<br >
     * 迭代对象为字符串
     *
     * @param method 测试方法名
     * @return java.lang.String 
     * @author ijfxu
     * @since 2021/1/27 00:17
     */
    @DataProvider
    @Override
    public Iterator<Object[]> dataProv(Method method) {
        String dataPath = getDataFilePath(method);
        return IteratorFactory.getIterator(dataPath);
    }

    /**
     * 数据工厂函数，返回测试入参迭代器对象;<br >
     * 迭代JSON格式数据并返回指定类型的参数
     *
     * @param method 测试方法名
     * @return java.util.Iterator 
     * @author ijfxu
     * @since 2021/5/23 14:06
     */
    @DataProvider
    public Iterator<Object[]> beanDataProv(Method method) {
        String dataPath = getDataFilePath(method);
        Class<?>[] ptypes = method.getParameterTypes();
        return IteratorFactory.getBeanIterator(dataPath, ptypes);

    }

    /**
     * 获取测试方法绑定的测试数据文件路径
     *
     * @param method 测试方法对象
     * @return java.lang.String 
     * @author ijfxu
     * @since 2021/1/27 00:17
     */
    @Override
    public String getDataFilePath(Method method) {
        /*获取默认的映射路径*/
        String classpath = method.getDeclaringClass().getName();
        String dir = RunContext.scriptDir;
        int index = classpath.indexOf(dir);
        String filePrePath = classpath.substring(index + dir.length() + 1);
        String[] prePathArr = filePrePath.split("\\.");
        String filePath = getFileWithName(join(getResource(RunContext.dataDir), join(prePathArr)), method.getName());

        if (null != filePath && !"".equals(filePath.trim())) {
            return filePath;
        }

        /*如果默认映射路径未发现数据文件则从数据文件注册集合中获取*/
        String methodName = method.getName();
        List<String> datas = TestDataCollection.getData(methodName);
        if (null == datas || datas.size() == 0) {
            log.err("no datafile with " + methodName);
            return null;
        }
        return datas.get(0);
    }


    /**
     * 根据sql数据库返回测试数据
     *
     * @param method 测试方法对象
     * @return java.util.Iterator
     * @throws java.sql.SQLException sql查询异常  
     * @author ijfxu
     * @since 2021/5/26 23:44
     */
    @DataProvider
    public Iterator<Object[]> sqldata(Method method) throws SQLException {
        Sql sql = method.getAnnotation(Sql.class);
        List<Entity> entities = null;
        if (!(empty(sql.url()) || isNull(sql.table()) || isNull(sql.user()) || isNull(sql.passwd()))) {
            DataSource ds = new SimpleDataSource(sql.url(), sql.user(), sql.passwd(), sql.driver());
            Connection conn = ds.getConnection();
            entities = SqlExecutor.query(conn, String.format("select * from %s", sql.table()), new EntityListHandler());
        } else {
            entities = Db.use(sql.group()).findAll(sql.table());
        }
        List<Object[]> datas = Convert.toList(Object[].class, entities);
        return datas.iterator();
    }
}
